/**
 * 版权所有(C)，上海海鼎信息工程股份有限公司，2009，所有权利保留。
 * 
 * 项目名：	rumba-widget2
 * 文件名：	LazyContainer.java
 * 模块说明：	
 * 修改历史：
 * Jan 24, 2009 - lxm - 创建。
 */
package com.hd123.rumba.gwt.widget2.client.panel;

import java.util.ArrayList;
import java.util.HashMap;

import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.Widget;

/**
 * 基于DOM，指定一个作为容器的Element，向其添加若干个Element。在添加时可以指定是否为滞后创建，如果选择是则这时并没有未被真正创建并添加，
 * 直到被调用的时候才会根据需要创建并添加；如果选择否，则添加当时将被创建。这样设计的目的是可以提高性能。
 * 
 * @author lxm
 * 
 */
public abstract class FlowPanelHelper {

  /**
   * 创建对象实例。
   * 
   * @param parent
   *            指定作为容器的Element。not null。
   */
  public FlowPanelHelper(FlowPanel parent) {
    super();
    if (parent == null)
      throw new RuntimeException("指定的参数parent不允许为null。");
    this.parent = parent;
  }

  private FlowPanel parent;
  /** List of String */
  private ArrayList names = new ArrayList();
  /** List of String, Element */
  private HashMap elements = new HashMap();

  /**
   * 取得作为容器的Element。
   * 
   * @return
   */
  public FlowPanel getParent() {
    return parent;
  }

  /**
   * 添加子Element到最后。
   * 
   * @param childName
   *            指定被加入的子Element的标识名。
   * @param lazy
   *            指定是否滞后创建。
   */
  public void appendChild(String childName, boolean lazy) {
    if (names.contains(childName))
      throw new RuntimeException("不可以重复加入相同的子元素(" + childName + ")。");
    names.add(childName);
    if (!lazy)
      getChild(childName);
  }

  /**
   * 插入子Element到指定的子Element之前。
   * 
   * @param childName
   *            指定被加入的子Element的标识名。
   * @param beforeName
   *            指定已经存在的子Element的标识名，将被添加到其之前的位置。
   * @param lazy
   *            指定是否滞后创建。
   */
  public void insertBefore(String childName, String beforeName, boolean lazy) {
    if (names.contains(childName))
      throw new RuntimeException("不可以重复加入相同的子元素(" + childName + ")。");
    int index = names.indexOf(beforeName);
    if (index == -1)
      throw new RuntimeException("指定的beforeName(" + beforeName + ")必须先被加入。");
    names.add(index, childName);
    if (!lazy)
      getChild(childName);
  }

  /**
   * 插入子Element到指定的位置。
   * 
   * @param childName
   *            指定被加入的子Element的标识名。
   * @param index
   *            指定插入位置的索引。
   * @param lazy
   *            指定是否滞后创建。
   */
  public void insertChild(String childName, int index, boolean lazy) {
    if (names.contains(childName))
      throw new RuntimeException("不可以重复加入相同的子元素(" + childName + ")。");
    names.add(index, childName);
    if (!lazy)
      getChild(childName);
  }

  /**
   * 取得指定子Element的索引。
   * 
   * @param childName
   *            指定子Element的标识名。
   * @return 从0开始计数，若不存在则返回-1。
   */
  public int getChildIndex(String childName) {
    return names.indexOf(childName);
  }

  /**
   * 取得所有子Element的数量。
   * 
   * @return
   */
  public int getChildCount() {
    return names.size();
  }

  /**
   * 取得指定的子Element。
   * 
   * @param childName
   *            指定子Element的标识名。
   * @return 若不存在则返回null。
   */
  public Widget getChild(String childName) {
    int index = names.indexOf(childName);
    if (index == -1)
      throw new RuntimeException("指定的子元素(" + childName + ")尚未被加入。");

    Widget w = (Widget) elements.get(childName);
    if (w != null)
      return w;

    w = createChild(childName);
    if (w == null)
      return w;

    // 取得下一个已经被创建出来的子Element。
    Widget next = null;
    index++;
    while (index < names.size()) {
      String name = (String) names.get(index);
      if (elements.containsKey(name)) {
        next = (Widget) elements.get(name);
        break;
      }
      index++;
    }

    if (next == null)
      parent.add(w);
    else {
      int beforeIndex = parent.getWidgetIndex(next);
      parent.insert(w, beforeIndex);
    }
    elements.put(childName, w);
    return w;
  }

  /**
   * 判断指定的子Element是否已经被创建。
   * 
   * @param childName
   *            指定子Element的标识名。
   * @return
   */
  public boolean isCreated(String childName) {
    return elements.containsKey(childName);
  }

  /**
   * 当需要创建子Element的时候被调用。
   * 
   * @param childName
   *            传入需要创建的子Element的名字。
   * @return 返回创建好的Element。如果返回null，则不作任何事。
   */
  protected abstract Widget createChild(String childName);

}
